package start;

import start.entity.Book;
import start.log.Address;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Java8Study01 {
    public static void main(String[] args) {
        forEach();
        System.out.println("------------------forEach");
        count();
        System.out.println("------------------count");
        filter();
        System.out.println("------------------filter");
        limit();
        System.out.println("------------------limit");
        skip();
        System.out.println("------------------skip");
        map();
        System.out.println("------------------map");
        sorted();
        System.out.println("------------------sorted");
        max();
        System.out.println("------------------isPresent");
        isPresent();
        System.out.println("------------------reduce");
        reduce();
        System.out.println("------------------selfMap");
        selfMap();
        System.out.println("------------------groupBy");
        groupBy();
        System.out.println("------------------optional");
        optional();
        System.out.println("------------------floatMap");
        floatMap();
    }



    public static void mapReduce() {
        List<Book> books = new ArrayList<>();
        for(int i=0; i<10; i++) {
            Book book = new Book();
            book.setAge(i);
            book.setName("li");
            books.add(book);
        }
         ;
        Book book1 = new Book();
        book1.setAge(1);
        book1.setName("t");
        books.add(book1);



        books.stream().reduce(0,(el1, el2) -> el1 + el2.getAge() , Integer::sum);
        System.out.println(books.stream().collect(Collectors

                .toMap(Book::getAge, Book::getName, (k1, k2) -> k1)));


        //Optional
    }

    private static void selfMap() {
        Date date = new Date();
        System.out.println(map(date, Date::getTime));

        /*System.out.println(map(date, new Function<Date, Long>() {
            @Override
            public Long apply(Date date1) {
                return date1.getTime();
            }
        }));*/
        Function<String, Integer> stringIntegerFunction = Integer::valueOf;
        /*Function<String, Integer> stringIntegerFunction = new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.valueOf(s);
            }
        };*/
        System.out.println((Integer) map("1", Integer::valueOf));
    }

    public static <T, R > R map(T t, Function<T, R> function) {
        return function.apply(t);
    }

    public static void test02() {
        Date date =new Date();
        //对象调用普通方法
        Supplier<Long> supplier01 = date::getTime;
        //类名调用静态方法
        Supplier<Long> supplier02 = System::currentTimeMillis;
        //类名调用普通方法，实际上是拿第一个参数作为实例对象
        Function<String, Integer> function01 = String::length;
        function01.apply("333333");

        Integer[] s = {1,2,3,4,5};

    }

    public static void forEach() {
        Stream<String> stringStream = Stream.of("1", "2", "3", "4");

        //自定义集合
        List<String> collect = stringStream.collect(Collector.of(
                new Supplier<List<String>>() {
                    @Override
                    public List<String> get() {
                        return new ArrayList<>();
                    }
                },
                new BiConsumer<List<String>, String>() {
                    @Override
                    public void accept(List<String> strings, String s) {
                        strings.add(s);
                    }
                },
                new BinaryOperator<List<String>>() {
                    @Override
                    public List<String> apply(List<String> list1, List<String> list2) {
                        list1.addAll(list2);
                        return list1;
                    }
                }
        ));
        collect.stream().forEach(System.out::println);
    }

    public static void count() {
        long count = Stream.of("1", "2", "3", "4").count();
        System.out.println(count);
    }

    private static void filter() {
        Stream.of("1","2","3","4")
                .filter(el -> "3".equals(el))
                .forEach(System.out::println);
    }

    private static void limit() {
        Stream.of("1","2","3","4")
                .limit(10)
                .forEach(System.out::println);
    }
    private static void skip() {
        Stream.of("1","2","3","4")
                .skip(10)
                .forEach(System.out::println);
    }


    private static void map() {
        Stream.of("1","2","3","4")
                .map(el -> el + ">>")
                .forEach(System.out::println);
    }

    private static void sorted() {
        /*Stream.of(1,3,2,4)
                .sorted().reduce()
                .forEach(System.out::println);*/
        int s = 0;
        Stu stu01 = new Stu(10, "张三");
        Stu stu02 = new Stu(6, "李四");
        Stu stu03 = new Stu(20, "王五");


        Stream.of(stu01, stu02, stu03)
                .sorted((el1, el2) -> el1.getAge() - el2.getAge() - s)
                .forEach(System.out::println);

    }

    private static void reduce() {
        Stu stu01 = new Stu(10, "张三");
        stu01.setSs(new BigDecimal("1"));
        Stu stu02 = new Stu(6, "李四");
        stu02.setSs(new BigDecimal("1"));
        Stu stu03 = new Stu(20, "王五");
        stu03.setSs(new BigDecimal("1"));
        Stu stu04 = new Stu();

        Stream<BigDecimal> integerStream = Stream.of(stu01, stu02, stu03, stu04)
                .map(stu -> {
                    System.out.println("map -执行");
                    return stu.getSs();
                })
                .filter(obj -> {
                    System.out.println("filter -执行");
                    return Objects.nonNull(obj);
                })
                .peek(x -> {
                    System.out.println("peek -执行");
                    System.out.println(x);
                });
        BigDecimal ss = integerStream.reduce(BigDecimal.ZERO, BigDecimal::add);
        System.out.println(ss);


        int age = Stream.of(stu01, stu02, stu03, stu04).map(Stu::getAge).filter(Objects::nonNull).reduce(0, Integer::sum);
        System.out.println(age);

    }

    private static void max() {
        Stu stu01 = new Stu(10, "张三");
        Stu stu02 = new Stu(6, "李四");
        Stu stu03 = new Stu(20, "王五");
        Stu stu = Stream.of(stu01, stu02, stu03)
                .max((el1, el2) -> el1.getAge() - el2.getAge())
                .get();
        System.out.println(stu);
    }

    private static void isPresent() {
        String s = "测试值呀";

        Stu stu = new Stu(10, "11");
        Stu stu01 = new Stu(10, null);
        /*Stu stu02 = new Stu(6, "李四");
        Stu stu03 = new Stu(20, "王五");
        Stu stu = Stream.of(stu01, stu02, stu03)
                .max((el1, el2) -> el1.getAge() - el2.getAge())
                .get();*/
        stu01.setName(Optional.ofNullable(stu01.getName()).map(el -> el + "111").orElse(s)) ;
        System.out.println(stu01);
        s = s + "111";
        //System.out.println(stu);
    }

    private static void groupBy() {
        List<Stu> stus = new ArrayList<>();

        Stu stu01= new Stu(10, new BigDecimal("30"),"11");
        Stu stu02 = new Stu(10, new BigDecimal("30"),"11");
        Stu stu03 = new Stu(10, new BigDecimal("30"),"11");
        Stu stu04 = new Stu(10, new BigDecimal("30"),"11");
        Stu stu05 = new Stu(10, new BigDecimal("30"),"11");
        Stu stu06 = new Stu(10, new BigDecimal("30"),"11");

        stus.add(stu01);
        stus.add(stu02);
        stus.add(stu03);
        stus.add(stu04);
        stus.add(stu05);
        stus.add(stu06);

        Map<String, List<Stu>> collect = stus.stream().collect(Collectors.groupingBy(Stu::getName));

        Map<String, List<Integer>> collect1 = stus.stream().collect(Collectors.groupingBy(Stu::getName, Collectors.mapping(Stu::getAge, Collectors.toList())));

        Map<String, Long> collect2 = stus.stream().collect(Collectors.groupingBy(Stu::getName, Collectors.counting()));

        collect2.keySet().stream().forEach(s -> System.out.println(s + "---" + collect2.get(s)));
        collect2.entrySet().stream().forEach(entry -> System.out.println(entry.getKey() + "---" + entry.getValue()));


        Map<String, BigDecimal> collect3 = stus.stream().collect(Collectors.groupingBy(Stu::getName, Collectors.reducing(BigDecimal.ZERO, Stu::getSs, BigDecimal::add)));
        System.out.println(collect3);


    }

    private static void optional() {

        SampleObjectT sampleObject = new SampleObjectT();

        String s = Optional.ofNullable(sampleObject).map(SampleObjectT::getStu).map(Stu::getName).orElse(null);
        System.out.println(s);

        Stu stu = new Stu();
        stu.setName("测试");
        sampleObject.setStu(stu);
        s = Optional.ofNullable(sampleObject).map(SampleObjectT::getStu).map(Stu::getName).orElse(null);
        System.out.println(s);


        sampleObject.setAddress(null);
        Optional.ofNullable(sampleObject)
                .map(SampleObjectT::getAddress)
                .map(el -> el.stream().map(Address::getCity)
                        .collect(Collectors.toList())).orElse(new ArrayList<>())
                .forEach(System.out::println);


        sampleObject.setAddress(new ArrayList<>());
        Address address = new Address();
        address.setCity("青岛");
        sampleObject.getAddress().add(address);

        address = new Address();
        address.setCity("烟台");
        sampleObject.getAddress().add(address);

        Optional.ofNullable(sampleObject)
                .map(SampleObjectT::getAddress)
                .map(el -> el.stream().map(Address::getCity)
                        .collect(Collectors.toList())).orElse(new ArrayList<>())
                .forEach(System.out::println);




    }



    private static void floatMap() {

        SampleObjectT sampleObject = new SampleObjectT();

        List<List<String>> list = new ArrayList<>();
        list.add(Arrays.asList("1", "2", "3"));
        list.add(Arrays.asList("4", "5", "6"));
        list.add(Arrays.asList("7", "8", "9"));
        List<String> stringList = list.stream().flatMap(new Function<List<String>, Stream<? extends String>>() {
            @Override
            public Stream<? extends String> apply(List<String> el) {
                return el.stream();
            }
        }).collect(Collectors.toList());
        System.out.println(stringList);

        Stream<String> stringStream1 = Stream.of("1", "2", "3");
        Stream<String> stringStream2 = Stream.of("4", "5", "6");
        Stream<String> stringStream3 = Stream.of("7", "8", "9");
        Stream<String> stringStream = Stream.of(stringStream1, stringStream2, stringStream3).flatMap(el -> el);
        System.out.println(stringStream.collect(Collectors.toList()));

    }





}

class Stu {

    Integer age;

    BigDecimal ss;

    String name;

    @Override
    public String toString() {
        return "Stu{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigDecimal getSs() {
        return ss;
    }

    public void setSs(BigDecimal ss) {
        this.ss = ss;
    }

    public Stu() {
    }

    public Stu(int age, String name) {
        this.age = age;
        this.name = name;


    }

    public Stu(Integer age, BigDecimal ss, String name) {
        this.age = age;
        this.ss = ss;
        this.name = name;
    }
}


class SampleObjectT {
    private int id;
    private String name;

    private Stu stu;

    private List<Address> address = new ArrayList<>();

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Address> getAddress() {
        return address;
    }

    public void setAddress(List<Address> address) {
        this.address = address;
    }

    public Stu getStu() {
        return stu;
    }

    public void setStu(Stu stu) {
        this.stu = stu;
    }
}
